#include <Assert.h>

#include <Manager/SignatureManager.h>
#include <Manager/NewsGroupManager.h>
#include <Manager/NewsManager.h>
#include <Manager/FileManager.h>

#include "DiscoverHandler.h"

using namespace std;
using namespace TCServer::Manager;

namespace TCServer
{
	namespace RPHandler
	{
		DiscoverHandler* DiscoverHandler::_instance = nullptr;
		DiscoverHandler::DiscoverHandler()
		{
			assert(_instance == nullptr);

			// for user
			setOn("discover/newsgroup/queryAll", this, &DiscoverHandler::queryAllNewsGroups);
			setOn("discover/news/queryAll", this, &DiscoverHandler::queryAllNews);

			// for admin
			setOn("discover/newsgroup/add", this, &DiscoverHandler::addNewsGroup);
			setOn("discover/newsgroup/update", this, &DiscoverHandler::updateNewsGroup);
			setOn("discover/newsgroup/remove", this, &DiscoverHandler::removeNewsGroup);
			setOn("discover/news/add", this, &DiscoverHandler::addNews);
			setOn("discover/news/update", this, &DiscoverHandler::updateNews);
			setOn("discover/news/remove", this, &DiscoverHandler::removeNews);
			_instance = this;
		}

		DiscoverHandler::~DiscoverHandler()
		{
			_instance = nullptr;
		}

		void DiscoverHandler::queryAllNewsGroups(QDataStream &stream, QVariantMap args)
		{
			auto res = SignatureManager::instance()->check(args.value("signature").toByteArray());

			if (get<bool>(res))
			{
				auto permissions = get<QSet<Type::Permission>>(res);
				if (permissions.contains(Type::Permission::User))
				{
					auto vals = NewsGroupManager::instance()->queryAll();
					QList<QVariantMap> objs;
					for (const auto &val : vals)
					{
						objs.append(val.toVairantMap());
					}
					stream << true << move(objs);
					return;
				}
			}
			stream << false;
		}

		void DiscoverHandler::queryAllNews(QDataStream &stream, QVariantMap args)
		{
			auto res = SignatureManager::instance()->check(args.value("signature").toByteArray());

			if (get<bool>(res))
			{
				auto permissions = get<QSet<Type::Permission>>(res);
				if (permissions.contains(Type::Permission::User))
				{
					auto groupId = args.value("groupId").toULongLong();
					auto vals = NewsManager::instance()->queryAll(groupId);
					QList<QVariantMap> objs;
					for (const auto &val : vals)
					{
						objs.append(val.toVairantMap());
					}
					stream << true << move(objs);
					return;
				}
			}
			stream << false;
		}

		void DiscoverHandler::addNewsGroup(QDataStream &stream, QVariantMap args)
		{
			auto res = SignatureManager::instance()->check(args.value("signature").toByteArray());
			if (get<bool>(res))
			{
				auto permissions = get<QSet<Type::Permission>>(res);
				if (permissions.contains(Type::Permission::Admin))
				{
					NewsGroupManager::instance()->insert(Type::NewsGroup::fromVariantMap(args));
					stream << true;
					return;
				}
			}
			stream << false;
		}

		void DiscoverHandler::updateNewsGroup(QDataStream &stream, QVariantMap args)
		{
			auto res = SignatureManager::instance()->check(args.value("signature").toByteArray());
			if (get<bool>(res))
			{
				auto permissions = get<QSet<Type::Permission>>(res);
				if (permissions.contains(Type::Permission::Admin))
				{
					NewsGroupManager::instance()
						->update(Type::NewsGroup::fromVariantMap(args));
					stream << true;
					return;
				}
			}
			stream << false;
		}

		void DiscoverHandler::removeNewsGroup(QDataStream &stream, QVariantMap args)
		{
			auto res = SignatureManager::instance()->check(args.value("signature").toByteArray());
			if (get<bool>(res))
			{
				auto permissions = get<QSet<Type::Permission>>(res);
				if (permissions.contains(Type::Permission::Admin))
				{
					auto id = args.value("id").toULongLong();
					NewsGroupManager::instance()->remove(id);
					stream << true;
					return;
				}
			}
			stream << false;
		}

		void DiscoverHandler::addNews(QDataStream &stream, QVariantMap args)
		{
            throw std::logic_error("" __FILE__ ", TCServer::RPHandler::DiscoverHandler::addNews(stream, args) is not implemented.");
			auto res = SignatureManager::instance()->check(args.value("signature").toByteArray());
			if (get<bool>(res))
			{
				auto permissions = get<QSet<Type::Permission>>(res);
				if (permissions.contains(Type::Permission::Admin))
				{
                    auto news = Type::News::fromVariantMap(args);
                    auto id = NewsManager::instance()->insert(news);
                    // TODO: move file from temp/ to news/
//                     FileManager::instance()->markUsed(news.contentUrl);
					stream << true;
					return;
				}
			}
			stream << false;
		}

		void DiscoverHandler::updateNews(QDataStream &stream, QVariantMap args)
		{
            throw std::logic_error("" __FILE__ ", TCServer::RPHandler::DiscoverHandler::updateNews(stream, args) is not implemented.");
			auto res = SignatureManager::instance()->check(args.value("signature").toByteArray());
			if (get<bool>(res))
			{
				auto permissions = get<QSet<Type::Permission>>(res);
				if (permissions.contains(Type::Permission::Admin))
                {
                    auto news = Type::News::fromVariantMap(args);
                    auto originalNews = NewsManager::instance()->query(news.id);

                    NewsManager::instance()->update(news);
                    FileManager::instance()->removeUrlAsync(originalNews.contentUrl);

                    // move file from temp/ to news/
//                     FileManager::instance()->markUsed(news.contentUrl);
					stream << true;
					return;
				}
			}
			stream << false;
		}

		void DiscoverHandler::removeNews(QDataStream &stream, QVariantMap args)
		{
			auto res = SignatureManager::instance()->check(args.value("signature").toByteArray());
			if (get<bool>(res))
			{
				auto permissions = get<QSet<Type::Permission>>(res);
				if (permissions.contains(Type::Permission::Admin))
				{
                    auto id = args.value("id").toULongLong();
                    auto originalNews = NewsManager::instance()->query(id);
                    NewsManager::instance()->remove(id);
                    FileManager::instance()->removeUrlAsync(originalNews.contentUrl);
					stream << true;
					return;
				}
			}
			stream << false;
		}

		DiscoverHandler* DiscoverHandler::instance()
		{
			if (_instance == nullptr)
				_instance = new DiscoverHandler;
			return _instance;
		}
	}
}

